
#include "commmsg.h"
#include "../mainctrl.h"
#include "../cmd/dataprepare.h"
#include "cmdcrystal.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_MINE_CRYSTAL, CCmdMineCrystal);

int CCmdMineCrystal::Do(void* pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_MINE_CRYSTAL ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_ALCHEMY,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdMineCrystal::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    ASSERT_PLAYER_PREPARED(uiGID);

    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    ASSERT_PLAYER_DETAIL_PREPARED(uiGID);

    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = 0;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerOnlineData & stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_17, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    //检查是否需要更新挖矿次数
    if (ReNewMineCount (stPlayerBaseInfo, stPlayerDetailInfo))
    {
        bNeedSaveDetailInfo = true;
    }

    unsigned char ucOpt = stReq.opt();

    //检查次数和背包
    int iCount = stReq.count();
    if (0 != ucOpt)
    {
        if (iCount <= 0)
        {
            CT_ERROR(("%d, %d", uiGID, iCount));
            return AnsClients(ERROR_MINE_CRYSTAL_COUNT);
        }

        int iMaxBatchCount = 0;
        int iRet = pstMainCtrl->m_stVipMgr.GetVipDestNum(stPlayerBaseInfo._chVipLevel, VIP_MODULE_ID_22, iMaxBatchCount);
        if (iRet)
        {
            CT_ERROR(("%d, %d", stPlayerBaseInfo._chVipLevel, iRet));
            return AnsClients(iRet);
        }
        

        if (iCount > iMaxBatchCount)
        {
            CT_ERROR(("%d, %d, %d", iCount, iMaxBatchCount, stPlayerBaseInfo._chVipLevel));
            return AnsClients(ERROR_BATCH_MINE_NOT_VIP);
        }

        if (stPlayerOnlineData._stUserStorage.BagIsFull())
        {            
            return AnsClients(ERROR_MINE_BAG_FULL);
        }
    }

    CDropItemData stDropData;    
    switch(ucOpt)
    {
    case 0: //查询信息
        {
            if (stReq.info_type() == 0)
            {
                for (int i = 1; i <= MINE_TYPE_MAX; i++)
                {
                    MsgMineCrystalInfo * pstMineInfo = (MsgMineCrystalInfo * )stAns.add_infos();
                    GetMineCrystalInfo(i, 1, *pstMineInfo);
                }
            }
            else
            {
                MsgMineCrystalInfo * pstMineInfo = (MsgMineCrystalInfo * )stAns.add_infos();
                GetMineCrystalInfo(stReq.info_type(), iCount, *pstMineInfo);
            }
        }
        break;
    case MINE_TYPE_LOW: //浅层开采
        {
            int iRealMineCount = 0;
            iRet = LowMineCrystal(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, iCount, iRealMineCount);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            pstMainCtrl->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_15, iRealMineCount);
            if (iRealMineCount > 0)
            {
                //保存数据
                bNeedSaveBaseInfo = true;
                bNeedSaveDetailInfo = true;
            }
        }
        break;
    
    case MINE_TYPE_DEEP: //深层开采
        {
            int iRealMineCount = 0;
            iRet = DeepMineCrystal(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, iCount, iRealMineCount);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            pstMainCtrl->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_16, iRealMineCount);
            if (iRealMineCount > 0)
            {
                //保存数据
                bNeedSaveBaseInfo = true;
                bNeedSaveDetailInfo = true;
            }
        }
        break;
  
    case MINE_TYPE_CORE: //核心开采
        {
            int iSolventCnt = pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage,
                                                                        ITEM_TYPE_SOLVENT, 1);
            if (iSolventCnt < CORE_MINE_NEED_SOLVENT_CNT)
            {
                return AnsClients(ERROR_LACK_SOLVENT);
            }

            CStorageGrid stDropGrid;
            for (int i = 0; i < iCount; i++)
            {
                if (stPlayerOnlineData._stUserStorage.BagIsFull())
                {
                    _iMineRet = ERROR_MINE_BAG_FULL;
                    return AnsClients(0);
                }

                int iSolventCnt = pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage,
                                                                           ITEM_TYPE_SOLVENT, 1);
                if (iSolventCnt < CORE_MINE_NEED_SOLVENT_CNT)
                {
                    _iMineRet = ERROR_LACK_SOLVENT;
                    return AnsClients(0);
                }

                iRet = pstMainCtrl->m_stStorageMgr.TakeOutItem(stPlayerOnlineData._stUserStorage, ITEM_TYPE_SOLVENT,
                                                               1, CORE_MINE_NEED_SOLVENT_CNT);
                if (iRet)
                {
                    _iMineRet = iRet;
                    return AnsClients(0);
                }

                bNeedSaveBaseInfo = true;
                bNeedSaveDetailInfo = true;

                stDropData.Clear();
                iRet = pstMainCtrl->m_stActMgr._stMineConfig.DropItem(MINE_TYPE_CORE, stDropData);
                if (iRet)
                {
                    CT_ERROR(("Drop Iitem failed: %d, %d", uiGID, MINE_TYPE_CORE));
                    _iMineRet = iRet;
                    return AnsClients(0);
                }

                short shItemCnt = stDropData._iItemCount;
                iRet = pstMainCtrl->m_stStorageMgr.AddItem(stPlayerOnlineData._stUserStorage, stDropData._ucItemType,
                    stDropData._usItemConfigID, shItemCnt);
                if (iRet)
                {
                    CT_ERROR(("Add Iitem failed: %d, %d, %d, %d, %d", uiGID, stDropData._ucItemType,
                                    stDropData._usItemConfigID, shItemCnt, shItemCnt));
                    _iMineRet = iRet;
                    return AnsClients(0);
                }

                _astAnsMineRet.Drop(stDropData);

                if (ITEM_TYPE_CRYSTAL == stDropData._ucItemType)
                {
                    CCrystalConfigData stConfigData;
                    pstMainCtrl->m_stItemMgr.GetCrystalConfig(stDropData._usItemConfigID, stConfigData);
                    if (stConfigData._usLevel >= 6)
                    {
                        MsgTips stTips;
                        stTips.set_type(1012);

                        stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
                        stTips.add_tip_argument(CTStringUtils::IntToString(MINE_TYPE_CORE));
                        stTips.add_tip_argument(CTStringUtils::IntToString(stDropData._usItemConfigID));
                        CMainCtrl::m_pstMain->SendOnlineTips(stTips);
                    }
                }
            }
        }
        break;

    default:
        return AnsClients(ERROR_MINE_TYPE_INVALID);
    }

    if (bNeedSaveDetailInfo)
    {
        pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);

        //触发任务
        pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_117, 1); //开采一次魔晶

    }

    return AnsClients(iRet);
}

int CCmdMineCrystal::AnsClients(int iRet)
{
    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    unsigned int uiNotifyType = 0;
    if (iIndex >= 0 && bNeedSaveBaseInfo)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex]._uiGID;
        pstMainCtrl->UpdateData(stKey, pstMainCtrl->m_stPlayerBaseInfoHash[iIndex], VOP_UPDATE);

        //刷新用户数据
        uiNotifyType = uiNotifyType | NOTIFY_USER_MONEY;        
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex >= 0 && bNeedSaveDetailInfo)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex]._uiGID;
        pstMainCtrl->UpdateData(stKey, pstMainCtrl->m_stPlayerDetailInfoHash[iIndex], VOP_UPDATE);

        //刷新用户数据
        uiNotifyType = uiNotifyType | NOTIFY_BAG_INFO;
    }

    pstMainCtrl->m_stNotifyMgr.Notify(uiGID, uiNotifyType);

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    if (iRet)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    stAns.set_gid(uiGID);
    stAns.set_opt(stReq.opt());
    stAns.set_ret(_iMineRet);
    if (0 != stReq.opt())
    {
        MsgMineCrystalInfo * pstMineInfo = (MsgMineCrystalInfo * )stAns.add_infos();
        GetMineCrystalInfo(stReq.opt(), 1, *pstMineInfo);
    }
    
    _astAnsMineRet.GetPBMsg(uiGID, *(stAns.mutable_get_items()));

    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true);

    return Done(RET_OK);
}

void CCmdMineCrystal::GetMineCrystalInfo(unsigned char ucMineType, int iMineCount, MsgMineCrystalInfo & stMineInfo)
{
    int iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return ;
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    stMineInfo.set_mine_type(ucMineType);
    unsigned ucCostType = 0;
    int iTotalCost= 0;
    int iCostValue = 0;
    int iAvailCount = 0;
    int iDiscount = 0;
    if (MINE_TYPE_LOW == ucMineType)
    {
        ucCostType = ITEM_TYPE_SILVER;
        iAvailCount = 65535;   //约定65535表示开采次数不受限制
        
        int iLeftCnt = 0;
        stPlayerDetailInfo._stMineData.GetLowMineCost(iDiscount, iCostValue, iLeftCnt);
        for (int i = 0; i < iMineCount; i++)
        {
            int iCurCost = 0;
            stPlayerDetailInfo._stMineData.GetLowMineCost(iDiscount, iCurCost, iLeftCnt, i);
            iTotalCost += iCurCost;
        }
        
        //如果当前折扣开采次数已经用完, 获取下级折扣的信息
        if (0 == iLeftCnt)
        {
            stPlayerDetailInfo._stMineData.GetLowMineCost(iDiscount, iCostValue, iLeftCnt, 1);
        }
        stMineInfo.set_lowminecnt(iLeftCnt);
    }
    else if (MINE_TYPE_DEEP == ucMineType)
    {
        ucCostType = ITEM_TYPE_GOLD;
        iCostValue = DEEP_MINE_NEED_GOLD_CNT;
        iTotalCost = DEEP_MINE_NEED_GOLD_CNT * iMineCount;
        iAvailCount = _iTodayMaxDeepMineCount - stPlayerDetailInfo._stMineData._iDeepMineCount;
    }
    else if (MINE_TYPE_CORE == ucMineType)
    {
        ucCostType = ITEM_TYPE_SOLVENT;
        iCostValue = CORE_MINE_NEED_SOLVENT_CNT;
        iTotalCost = CORE_MINE_NEED_SOLVENT_CNT * iMineCount;
        iAvailCount = 65535;   //约定65535表示开采次数不受限制
    }
    else
    {
        CT_ERROR(("%d", ucMineType));
        return ;
    }

    stMineInfo.set_cost_type(ucCostType);
    stMineInfo.set_cost_value(iCostValue);
    stMineInfo.set_count(iAvailCount);
    stMineInfo.set_total_cost(iTotalCost);
    if (0 == stReq.opt())
    {
        stMineInfo.set_query_cnt(stReq.count());
    }
    stMineInfo.set_discount(iDiscount);
    return ;
}

bool CCmdMineCrystal::ReNewMineCount (CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo)
{
    //根据VIP等级,计算深层开采次数
    _iTodayMaxDeepMineCount = GetDeepMineCountPerDay(stPlayerBaseInfo);

    const int & iNowTime = pstMainCtrl->m_iNow;
    if (iNowTime > stPlayerDetailInfo._stMineData._iClearTime)   
    {
        int iNextClearTime = CTTimeUtils::GetDayBeginSec(iNowTime) + MINE_CRYSTAL_CLEAR_TIME;           
        if (iNowTime >= iNextClearTime)
        {
            iNextClearTime += 86400;
        }        
        
        stPlayerDetailInfo._stMineData._iClearTime = iNextClearTime;
        stPlayerDetailInfo._stMineData._iLowMineCount = 0;
        stPlayerDetailInfo._stMineData._iDeepMineCount = 0;

        return true;
    }
    

    return true;
}


int  CCmdMineCrystal::GetDeepMineCountPerDay (CPlayerBaseInfo & stPlayerBaseInfo)
{
    int iMaxResetCount = 0;
    int iRet = pstMainCtrl->m_stVipMgr.GetVipDestNum(stPlayerBaseInfo._chVipLevel, VIP_MODULE_ID_8, iMaxResetCount);
    if (RET_OK != iRet)
    {
        CT_ERROR(("%d, %d, %d", stPlayerBaseInfo._uiGID, stPlayerBaseInfo._chVipLevel, iRet));
        return 0;
    }

    return iMaxResetCount;
}

int CCmdMineCrystal::LowMineCrystal(CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo & stPlayerDetailInfo,CPlayerOnlineData & stPlayerOnlineData, int iCount, int & iRealMineCount)
{
    iRealMineCount = 0;

    //获取价格
    int iCostValue = 0;
    int iDiscount = 0;
    int iRet = RET_OK;

    CDropItemData stDropData;
    CMineCrystalData & stMineCrystal = stPlayerDetailInfo._stMineData;
    for (int i = 0; i < iCount; i++)
    {
        if (stPlayerOnlineData._stUserStorage.BagIsFull())
        {
            _iMineRet = ERROR_MINE_BAG_FULL;
            break;
        }

        int iLeftCnt = 0;
        stMineCrystal.GetLowMineCost(iDiscount, iCostValue, iLeftCnt);

        iRet = CPlayerBaseInfo::CheckInt64Value(stPlayerBaseInfo._i64Silver,  0 - iCostValue);
        if (iRet != RET_OK)
        {
            _iMineRet = ERROR_SILVER_LESS;
            break;
        }

        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubSilver(stPlayerBaseInfo, iCostValue, 0);
        if (iRet != RET_OK)
        {
            _iMineRet = ERROR_SILVER_LESS;
            break;
        }

        stDropData.Clear();
        iRet = pstMainCtrl->m_stActMgr._stMineConfig.DropItem(MINE_TYPE_LOW, stDropData);
        if (iRet)
        {
            CT_ERROR(("Drop Iitem failed: %d, %d", uiGID, MINE_TYPE_LOW));
            _iMineRet = iRet;
            break;
        }

        short shItemCnt = stDropData._iItemCount;
        iRet = pstMainCtrl->m_stStorageMgr.AddItem(stPlayerOnlineData._stUserStorage, stDropData._ucItemType,
                                                   stDropData._usItemConfigID, shItemCnt);
        if (iRet)
        {
            CT_ERROR(("Add Iitem failed: %d, %d, %d, %d, %d", uiGID, stDropData._ucItemType,
                stDropData._usItemConfigID, shItemCnt, shItemCnt));
            _iMineRet = iRet;
            break;
        }

        stPlayerDetailInfo._stMineData._iLowMineCount += 1;
        _astAnsMineRet.Drop(stDropData);

        if (ITEM_TYPE_CRYSTAL == stDropData._ucItemType)
        {
            CCrystalConfigData stConfigData;
            pstMainCtrl->m_stItemMgr.GetCrystalConfig(stDropData._usItemConfigID, stConfigData);
            if (stConfigData._usLevel >= 6)
            {
                MsgTips stTips;
                stTips.set_type(1012);

                stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
                stTips.add_tip_argument(CTStringUtils::IntToString(MINE_TYPE_LOW));
                stTips.add_tip_argument(CTStringUtils::IntToString(stDropData._usItemConfigID));
                CMainCtrl::m_pstMain->SendOnlineTips(stTips);
            }
        }

        iRealMineCount += 1;
    }

    return RET_OK;
}


int CCmdMineCrystal::DeepMineCrystal(CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo & stPlayerDetailInfo,
                                     CPlayerOnlineData & stPlayerOnlineData, int iCount, int & iRealMineCount)
{
    int iRet = RET_OK;
    CDropItemData stDropData;

    CMineCrystalData & stMineCrystal = stPlayerDetailInfo._stMineData;

    iRealMineCount = 0;
    if (stMineCrystal._iDeepMineCount >= _iTodayMaxDeepMineCount)
    {
        return ERROR_TODAY_REACH_MAX;
    }

    for (int i = 0; i < iCount; i++)
    {
        if  (stMineCrystal._iDeepMineCount >= _iTodayMaxDeepMineCount)
        {
            _iMineRet = ERROR_TODAY_REACH_MAX;
            break;
        }

        if (stPlayerOnlineData._stUserStorage.BagIsFull())
        {
            _iMineRet = ERROR_MINE_BAG_FULL;
            break;
        }

        if (stPlayerBaseInfo._iGold < DEEP_MINE_NEED_GOLD_CNT)
        {
            _iMineRet = ERROR_GOLD_LESS;
            break;
        }

        //扣除金币
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_05, DEEP_MINE_NEED_GOLD_CNT);
        if (iRet != RET_OK)
        {
            _iMineRet = ERROR_GOLD_LESS;
            break;
        }

        stDropData.Clear();
        iRet = pstMainCtrl->m_stActMgr._stMineConfig.DropItem(MINE_TYPE_DEEP, stDropData);
        if (iRet)
        {
            CT_ERROR(("Drop Iitem failed: %d", uiGID));
            _iMineRet = iRet;
            break;
        }

        short shItemCnt = stDropData._iItemCount;
        iRet = pstMainCtrl->m_stStorageMgr.AddItem(stPlayerOnlineData._stUserStorage, stDropData._ucItemType,
            stDropData._usItemConfigID, shItemCnt);
        if (iRet)
        {
            CT_ERROR(("Add Iitem failed: %d, %d, %d, %d, %d", uiGID, stDropData._ucItemType,
                stDropData._usItemConfigID, shItemCnt, shItemCnt));
            _iMineRet = iRet;
            break;
        }

        stPlayerDetailInfo._stMineData._iDeepMineCount += 1;
        iRealMineCount += 1;
        _astAnsMineRet.Drop(stDropData);

        if (ITEM_TYPE_CRYSTAL == stDropData._ucItemType)
        {
            CCrystalConfigData stConfigData;
            pstMainCtrl->m_stItemMgr.GetCrystalConfig(stDropData._usItemConfigID, stConfigData);
            if (stConfigData._usLevel >= 6)
            {
                MsgTips stTips;
                stTips.set_type(1012);

                stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiGID));
                stTips.add_tip_argument(CTStringUtils::IntToString(MINE_TYPE_DEEP));
                stTips.add_tip_argument(CTStringUtils::IntToString(stDropData._usItemConfigID));
                CMainCtrl::m_pstMain->SendOnlineTips(stTips);
            }
        }
    }

    return RET_OK;
}
